#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include "Log.hpp"
#include "Epoller.hpp"
#include "nocopy.hpp"
#include "sockfd.hpp"
#include <unordered_map>
#include "comm.hpp"
class Connection;
class TCPServer;
using func_t = std::function<void*(std::shared_ptr<Connection>)>;
const uint16_t defaultport = 8888;
uint32_t EVENT_IN = (EPOLLIN);   // 读
uint32_t EVENT_OUT = (EPOLLOUT); // 写

class Connection : public nocopy
{
public:
    Connection(int sock, std::shared_ptr<TCPServer> tcp_server_ptr)
        : _sock(sock),
          _tcp_server_ptr(tcp_server_ptr)
    {
    }
    void SetHandler(func_t recv_cd, func_t send_cd, func_t except_cd)
    {
        _recv_cb = recv_cd;
        _send_cb = send_cd;
        _except_cb = except_cd;
    }
    ~Connection()
    {
    }
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    int sockfd()
    {
        return _sock;
    }
private:
    int _sock;
    std::string _inbuffer;
    std::string _outbuffer;

    std::shared_ptr<TCPServer> _tcp_server_ptr;
};

class TCPServer
{
    static const int num = 64;

public:
    TCPServer(uint16_t port = defaultport)
        : _port(port),
          _epoller_ptr(new Epoller()),
          _quit(true),
          _listen_ptr(new Sock())
    {
        _listen_ptr->Socket();
        _listen_ptr->Bind(_port);
        _listen_ptr->Listen();
        setNonBlock(_listen_ptr->Fd());
        lg(Info, "creat listen socket success %d\n", _listen_ptr->Fd());
        AddConection(_listen_ptr->Fd(), EVENT_IN,\
        std::bind(&TCPServer::Accepter,this,std::placeholders::_1), nullptr, nullptr);
    }
    void Init()
    {
    }
    void AddConection(int sock, uint32_t event, func_t recv_cd, func_t send_cd, func_t except_cd)
    {
        _epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD, sock, EVENT_IN);
        std::shared_ptr<Connection> connection_ptr = std::make_shared<Connection>(sock, std::shared_ptr<TCPServer>(this));

        connection_ptr->SetHandler(recv_cd, send_cd, except_cd);

        _connect.insert(std::make_pair(sock, connection_ptr));
    }
    bool IsConnection(int sock)
    {
        auto iter = _connect.find(sock);
        if (iter == _connect.end())
            return false;
        else
            return true;
    }
    void Accepter(std::shared_ptr<Connection> connection)
    {
        while(true){
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = ::accept(connection->sockfd(),(struct sockaddr*)&peer,&len);
            if(sock > 0)
            {
                setNonBlock(sock);
                AddConection(sock,EVENT_IN,nullptr,nullptr,nullptr);
            }
            else{
                if(errno == EWOULDBLOCK)break;//读完
                else if(errno == EINTR)continue;//信号唤醒
                else
                    break;
            }
        }
    }
    void DisPacher(int timeout)
    {
        int n = _epoller_ptr->EpollWait(revs, num);
        for (int i = 0; i < n; i++)
        {
            uint32_t event = revs[i].events;
            int sock = revs[i].data.fd;
            if (event & EPOLLERR)
                event |= (EPOLLIN | EPOLLOUT);
            if (event & EPOLLHUP)
                event |= (EPOLLIN | EPOLLOUT);
            if (event & EPOLLIN && IsConnection(sock))
            {
                if (_connect[sock]->_recv_cb)
                    _connect[sock]._recv_cb(_connect[sock]);
            }
            if (event & EPOLLOUT && IsConnection(sock))
            {
                if (_connect[sock]->_send_cb)
                    _connect[sock]._send_cb(_connect[sock]);
            }
        }
    }
    void Loop()
    {
        _quit = false;
        //_epoller_ptr->EpollerUpdate(EPOLL_CTL_ADD,_listen_ptr->Fd(),EVENT_IN);
        // AddConection();
        while (!_quit)
        {
            int n = _epoller_ptr->EpollWait(revs, num);
            for (int i = 0; i < n; i++)
            {
                DisPacher(3000);
            }
        }
        _quit = true;
    }
    ~TCPServer() {}

private:
    std::shared_ptr<Sock> _listen_ptr;
    std::shared_ptr<Epoller> _epoller_ptr;
    std::unordered_map<int, std::shared_ptr<Connection>> _connect;
    uint16_t _port;
    bool _quit;
    struct epoll_event revs[num];
};